Skip to content

feat: add hub funded spoke pool testnet VIP - #762

Open
Debugger022 wants to merge 5 commits into
mainfrom
feat/hub-spoke-pool-testnet-vip
Open

feat: add hub funded spoke pool testnet VIP#762
Debugger022 wants to merge 5 commits into
mainfrom
feat/hub-spoke-pool-testnet-vip

Conversation

@Debugger022

@Debugger022 Debugger022 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

What this VIP does

Phase 1 of the Hub-Funded Spoke pool on BNB Chain testnet. Covers the spoke pool side only (isolated-pools#559). Liquidity Hub wiring (venus-liquidity-hub#22) and bStock liquidation (venus-protocol#707) are Phase 2.

Executed on bsctestnet on 2026-09-09 as GovernorBravo proposal 715.

  1. Accept ownership of the spoke Comptroller and the spoke PoolRegistry
  2. Grant 18 ACM roles (details below)
  3. Set the ResilientOracle and the DeviationBoundedOracle on the Comptroller, and give USDC the same price window configuration USDT already carries
  4. Upgrade ProtocolShareReserve and register the spoke registry as an additional registry
  5. Move the risk fund's 20% income share from RiskFundConverter to RiskFundBuyback
  6. Register the pool and list 2 markets: USDT (liquidity) and USDC (collateral)
  7. Set per-market liquidation incentives, and arm the USDT supply allowlist with no members

44 commands. Every address is deployed and was read back from bsctestnet. Covered end to end by simulations/vip-671/bsctestnet.ts, which asserts the pre-VIP state, the permissions the VIP assumes rather than grants, every command, and the post-VIP state.

Permissions

Grantee Roles
SpokePoolRegistry the 6 Comptroller setters it drives inside addPool and addMarket
Normal Timelock the 6 spoke-only roles
Guardian the same 6 spoke-only roles, testnet only
FastTrack, Critical timelocks none

Everything else is already covered by wildcard grants on this chain, verified on chain rather than assumed.

Two things worth calling out. The registry grants are the easy miss: the identical wildcards exist but name the isolated-pools registry as the account, so the spoke registry inherits none and addPool reverts without them. And the Guardian grants are a bsctestnet decision, so QA can arm and lift either allowlist and flip forced liquidation without a proposal per test case. A mainnet listing should grant these to the Normal Timelock alone. The pause path already reaches all three timelocks through existing wildcards, which is why the emergency timelocks receive nothing here.

Notes

  • The spoke pool is listed through a PoolRegistry of its own, so it stays out of the directory the indexer, frontend and risk tooling iterate. The Comptroller takes that registry as a constructor immutable with no setter.
  • Step 4 depends on protocol-reserve#168 being deployed. The upgrade and addPoolRegistry stay in the same proposal, per that PR. Without it every liquidation in the pool reverts, since vTokens call updateAssetsState on both the reserve and the seize path.
  • Step 5 fixes config drift. RiskFundConverter is still a 20% income destination on testnet but was retired on mainnet in VIP-618, and it is the one destination that cannot resolve a pool outside its own registry. The share is unchanged, only the destination.
  • Risk parameters come from isolated-pools helpers/spokeDeploymentConfig.ts, the file the deployment was run from, so the listing matches what was deployed. They mirror the isolated Stablecoins pool on this network, because a spoke pool restricts who may supply, borrow and liquidate rather than taking more risk per market.
  • Both markets are listed with identical risk parameters. What makes this a spoke pool is not deployment input: the liquidity side is metered by arming its supply allowlist after addMarket. That happens in step 7 with no members, so the market is closed to supply from the moment it is listed and can never be supplied permissionlessly in the window before the Hub arrives. Phase 2 adds the Hub's spoke source with setAllowedSupplier.
  • The USDC market is left permissionless. PRD FR-4 makes the collateral-deposit allowlist optional and off by default.
  • Redeeming is never gated, and the seed liquidity minted to the treasury at listing is unaffected.
  • The bStock markets named in PRD section 6 are not listed here. Their liquidation leg is Phase 2: BStockLiquidator is not deployed on this chain at all.

Known follow-up, not blocking

RiskFundConverter still resolves through a single registry. It stops being a PSR destination after step 5, so it does not affect this launch, but it needs the same multi-registry treatment before any spoke pool reaches mainnet. Noted on protocol-reserve#168.

- Foundation draft only. The spoke comptroller, markets, adapter and
  yield source are unbuilt, so their addresses are zero placeholders
  and the proposal cannot be simulated until they land.
- Command order is load-bearing in four places: acceptOwnership before
  any owner-gated setter, setPriceOracle before addPool, the bounded
  oracle before the pool serves a borrow or redeem, and addMarket
  before the supply allowlist is armed.
- Grants only the six ACM roles this chain does not already cover.
  The rest are held by the timelock or the registry as wildcards,
  checked on chain
- Risk parameters the PRD does not specify are left as TODO, as are the bStock liquidation calls, which have no testnet target yet.
@Debugger022 Debugger022 self-assigned this Sep 2, 2026
…ase 1

- Refined comments and descriptions in config.ts for clarity and accuracy regarding pool mechanics and risk factors.
- Adjusted liquidation incentive and collateral factor definitions to align with updated PRD references.
- Enhanced the permissions.ts file to include necessary role strings for the new Spoke pool, ensuring proper access control.
- Added comments to clarify the implications of wildcard grants and the necessity of specific role grants for the new registry.
- Introduced new roles for governance and registry-driven actions, ensuring smooth operation of the Spoke pool.
@Debugger022
Debugger022 marked this pull request as ready for review September 8, 2026 12:26
@greptile-apps

greptile-apps Bot commented Sep 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces the BNB Chain testnet Phase 1 VIP for a Hub-Funded Spoke pool.

  • Adds a network-specific address book and four-market configuration.
  • Encodes ownership acceptance, ACM grants, oracle configuration, and pool/market registration.
  • Upgrades ProtocolShareReserve for an additional registry and migrates the risk-fund distribution destination.
  • Enables an empty supply allowlist for the USDT liquidity market.
  • The proposal remains non-executable because deployment addresses, risk approval, and simulation coverage are outstanding.

Confidence Score: 4/5

The PR is not safe to use or merge as an executable VIP until proposal-consumed zero addresses are replaced; the unresolved risk configuration and missing simulation should also be addressed.

The proposal deterministically attempts to configure zero-address spoke contracts and upgrade ProtocolShareReserve to a zero implementation, so governance execution cannot complete in its current form. The remaining findings concern risk sign-off, unused IRM configuration, and absent regression coverage.

Files Needing Attention: vips/vip-671/addresses/bsctestnet.ts, vips/vip-671/bsctestnet.ts, vips/vip-671/config.ts

Important Files Changed

Filename Overview
vips/vip-671/addresses/bsctestnet.ts Adds the testnet address book, but proposal-critical spoke and implementation addresses remain zero placeholders.
vips/vip-671/bsctestnet.ts Builds the ordered governance payload, but lacks fork simulation and does not apply or verify configured market IRMs.
vips/vip-671/config.ts Defines four markets and reserve distribution constants, with several materially consequential risk values still awaiting approval.
vips/vip-671/permissions.ts Defines registry and governance ACM roles using a command-builder pattern consistent with existing VIPs.

Reviews (1): Last reviewed commit: "feat(: update Hub-Funded Spoke pool para..." | Re-trigger Greptile

Comment thread vips/vip-671/addresses/bsctestnet.ts Outdated
Comment on lines +96 to +104
export const PROTOCOL_SHARE_RESERVE_IMPL = "0x0000000000000000000000000000000000000000";

/// TODO(deploy): isolated-pools `deploy/024-deploy-spoke-pool-registry.ts` -> `SpokePoolRegistry`.
/// A SECOND `PoolRegistry` instance, behind the chain's existing DefaultProxyAdmin. The spoke pool is
/// deliberately kept out of the isolated-pools directory that the indexer, the frontend pool list and
/// the risk tooling all iterate.
/// `Ownable2Step`: the deploy script only NOMINATES the Normal Timelock, so this VIP must call
/// `acceptOwnership()` before `addPool`.
export const SPOKE_POOL_REGISTRY = "0x0000000000000000000000000000000000000000";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Proposal targets zero addresses

The executable proposal still uses zero-address placeholders for the spoke registry, comptroller, markets, and new reserve implementation. If vip671 is submitted in this state, its calls cannot configure the spoke contracts, and the ProxyAdmin upgrade to the zero implementation will revert, preventing proposal execution. Replace every address consumed by the proposal before merging the executable VIP.

Comment thread vips/vip-671/config.ts Outdated
Comment on lines +136 to +157
collateralFactor: parseUnits("0.75", 18), // PRD §6
liquidationThreshold: parseUnits("0.8", 18), // PRD §6
supplyCap: parseUnits("236", 18), // TODO(risk): copied from VIP-633's Core listing.
};

export const MARKET_NVDAB: SpokeMarket = {
...collateralDefaults,
symbol: "vNVDAB_HubSpoke",
vToken: VNVDAB_SPOKE,
underlying: NVDAB,
collateralFactor: parseUnits("0.75", 18), // PRD §6
liquidationThreshold: parseUnits("0.8", 18), // PRD §6
supplyCap: parseUnits("450", 18), // TODO(risk): copied from VIP-633's Core listing.
};

export const MARKET_SPCXB: SpokeMarket = {
...collateralDefaults,
symbol: "vSPCXB_HubSpoke",
vToken: VSPCXB_SPOKE,
underlying: SPCXB,
collateralFactor: parseUnits("0.7", 18), // PRD §6
liquidationThreshold: parseUnits("0.75", 18), // PRD §6

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Risk values remain unapproved

These collateral factors and liquidation thresholds are explicitly unresolved risk placeholders, but proposal tooling does not prevent them from entering the governance payload. Compared with VIP-633 for the same assets, these factors allow 25% more borrowing for TSLAB and NVDAB and 40% more for SPCXB. Obtain risk approval and replace or explicitly validate these values before making the proposal executable.

- give the guardian the same six spoke comptroller roles as the normal
  timelock. testnet only, so testing can add a supplier, lift an
  allowlist or force a liquidation without a proposal each time
- move the "already granted on this chain" list out of comments into
  ASSUMED_WILDCARD_ROLES and assert it before the proposal runs, so a
  revoked wildcard fails the simulation instead of the execution
- assert the ownership the reserve upgrade and addPoolRegistry rest on
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant